#ifndef Simulator_h
#define Simulator_h

#include "Process.h"
#include "Scheduler.h"
#include <cstdarg>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <list>

using namespace std;

typedef struct {
	// ----------------
	// Final Statistics
	// ----------------
	
	// Queuing time - time a task spends waiting to be run (total time it is not active after it has been issued)
	unsigned long queuingWorst;
	double queuingAverage;
	// Turnaround time - # cycles between when a task is first issued and when it finishes
	unsigned long turnaroundWorst;
	double turnaroundAverage;
	// % of tasks that met their deadlines
	double percentDeadlinesMet;

	// --------------
	// Running Totals
	// --------------
	unsigned long count;
	unsigned long countMetDeadlines;
	unsigned long countMissedDeadlines;

} Results;



class Simulator {
	public:
		Simulator();
		int LoadScript(const char * filename);
		void Run(Scheduler * schedArg, bool traceModeEnabledArg = false, bool preemptBlocksEnabled = false, unsigned long processSwitchCyclesArg = 0);
	private:
		// Used by LoadScript() to clear out the process and definitions maps
		void ClearProcesses();
		void ClearDefinitions();

		// Used by Run() to initialize the Results structs to a zeroed out state
		void ClearResults();
	
		// Used by Run() to simulate the CPU execution and scheduling
		void InitializeRun();
		void IssueProcesses();
		void UpdateBlockingStatus(Process * p);
		void UnblockProcesses();
		void ProcessSwitch();
		void ProcessFinished(Process * p);
		void PrintResults();
		void PrintTrace(const char * format, ...);

		// Initialized by LoadScript() and used by Run()
		map <unsigned long, vector <Process *> *> processes; // The set of all processes keyed on issue time
		unsigned long processCount; // The total number of processes

		// Used by Run() to contain the parameters of the simulation
		bool traceModeEnabled; // Determines whether trace lines print or not
		unsigned long processSwitchCycles; // The number of cycles of overhead for process switching
		Scheduler * sched; // The current Scheduler to consult for scheduling decisions

		// Used by LoadScript() to save process definitions
		map <string, Process *> processDefs; // Contains the process definition lines for handling the issue lines
		
		// Used by Run() to track results
		map <string, Results *> procResults; // Results for each process name	
		unsigned long countBlockedCycles; // Incremented when active process is blocking
		unsigned long countActiveCycles; // Incremented when the active process is not blocking
		unsigned long countProcessSwitchCycles; // Incremented when there is not an active process, because a process switch is occurring

		// Used by Run() to track progress
		list <Process *> blockingProcesses; // The list of processes currently blocking
		unsigned long finishedCount; // The number of processes that have finished
		Process * lastActiveProcess; // Determines whether a process switch occurred or not 
		unsigned long clockCycle; // The current clock cycle (starts at 0)
};

#endif
